using System;
using System.Collections.Generic;
using System.Text;

using System.Windows.Forms;

using System.Xml;

using ClientGUI.Util;
using ClientGUI.Modules;
using ClientGUI.Modules.Drawing;
using ClientGUI.Widgets.Support;
using System.Drawing;

using OWED.Document;

namespace ClientGUI
{
    class DocumentEditor: Control
    {
        DisplayDocument my_display;
        DisplayProperties my_attribute_view;
        DisplayChildTags my_child_view;
        public DocumentEditor()
            :base()
        {
            my_display = new DisplayDocument();
            my_attribute_view = new DisplayProperties();
            my_child_view = new DisplayChildTags(my_display);

            my_display.ModuleSelected += ModuleSelected;

            
            Controls.Add(my_display);
            Controls.Add(my_attribute_view);
            Controls.Add(my_child_view);

            my_child_view.ListView.ItemDrag += new ItemDragEventHandler(ListView_ItemDrag);
            my_child_view.ListView.DragLeave += new EventHandler(ListView_DragLeave);
            my_child_view.ListView.DragOver += new DragEventHandler(ListView_DragOver);

            Resize += new EventHandler(DocumentEditor_Resize);
            Width = Width+1;


            //editing callbacks
            my_display.MouseDown += new MouseEventHandler(DisplayDocument_MouseDown);
            my_display.MouseUp += new MouseEventHandler(DisplayDocument_MouseUp);
            my_display.MouseMove += new MouseEventHandler(DisplayDocument_MouseHover);
            KeyUp += new KeyEventHandler(my_display_KeyUp);
        }

        

        void ListView_DragOver(object sender, DragEventArgs e)
        {
            throw new Exception("The method or operation is not implemented.");
        }

        void ListView_DragLeave(object sender, EventArgs e)
        {
            throw new Exception("The method or operation is not implemented.");
        }

        void ListView_ItemDrag(object sender, ItemDragEventArgs e)
        {
            my_child_view.DoDragDrop(my_child_view.ListView.SelectedItems[0].SubItems[0].Text,
                DragDropEffects.Copy);
        }


        public List<ChangeAtom> Changes { 
            get { return my_display.Changes; }
            set
            {
                my_display.Changes = value;
            }
        }

        public void SetDocument(XmlDocument doc)
        {
            my_display.SetDocument(doc);
        }
        public XmlDocument GetDocument()
        {
            return my_display.GetDocument();
        }

        public Configuration Config
        {
            get
            {
                return my_display.Config;
            }
            set
            {
                my_display.Config = value;
            }
        }

        void DocumentEditor_Resize(object sender, EventArgs e)
        {
            if (Width < 250)
            {
                Width = 250;
                return;
            }
            my_display.Top = 0;
            my_display.Left = 0;
            my_attribute_view.Top = 0;
            my_attribute_view.Width = 150;

            my_display.Width = Width - 150;
            my_attribute_view.Left = my_display.Width;

            my_display.Height = Height;
            my_attribute_view.Height = Height/2;

            my_child_view.Height = Height / 2;
            my_child_view.Width = my_attribute_view.Width;
            my_child_view.Top = my_attribute_view.Height;
            my_child_view.Left = my_attribute_view.Left;
        }

        public void RemoveSelected()
        {
            my_display.RemoveSelected();
        }

        private void ModuleSelected(Module m)
        {
            my_attribute_view.Use(m);
            my_child_view.Use(m);
        }


        #region DOCUMENTEDITING
        /// <summary>
        /// The currently inserted D&amp;D blank widget.
        /// </summary>
        private Module my_temp_insert = null;

        /// <summary>
        /// Currently selected module.
        /// </summary>
        private Module my_current_selected = null;

        /// <summary>
        /// Inserts the blank node in at the given point.
        /// This is for use by the mouse over.
        /// </summary>
        private void insert_blank(Blank blank, Module under, int loc)
        {
            if (my_temp_insert != null &&
                my_temp_insert.Parent == under &&
                my_temp_insert.Parent.Children.IndexOf(my_temp_insert) == loc)
            {
                //do nothing!
                return;
            }
            if (my_temp_insert != null &&
                my_temp_insert.Parent == under &&
                my_temp_insert.Parent.Children.IndexOf(my_temp_insert) == loc - 1)
                return;


            if (my_temp_insert != null)
            {
                my_temp_insert.Parent.Children.Remove(my_temp_insert);
                my_temp_insert = null;
            }

            under.Children.Insert(loc, blank);
            my_temp_insert = blank;

            AnimatorCallback call = delegate(int val)
            {
                blank.SetHeight(val);
                Refresh();
            };

            int height = blank.Height; //doesn't animate for some reason...

            Animator a = new Animator(0, blank.Height + blank.Height / 2, 50, call, 2);
            a.Animate();
            blank.SetHeight(height);
        }

        /// <summary>
        /// Gives a hover when not clicked.
        /// Gives a drag and drop effect when something is being dragged.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void DisplayDocument_MouseHover(object sender, MouseEventArgs e)
        {
            if (my_clicked == null)
            {
                MouseEventArgs args = e as MouseEventArgs;
                my_display.MouseHover(args.X, args.Y);
            }
            else
            {
                if (e.Y <= 50)
                {
                    my_display.Scroll(-100);
                }
                DisplayElement cur = my_display.ModuleAtCoordinate(e.X, e.Y);
                if (cur != null)
                {
                    //first draw blank area
                    Blank temp_mod = new Blank(my_display, null, Color.Gray);
                    temp_mod.SetHeight(30);
                    Module last = null;
                    int offset = 10;
                    while (true)
                    {
                        DisplayElement el = my_display.ModuleAtCoordinate(e.X, e.Y - offset);
                        if (el != null)
                            last = el.Displayed;

                        if (last != null)
                        {
                            if (cur.Displayed.Parent == null)
                            { }
                            else if (cur.Displayed.Parent.Children.Contains(last))
                                break;
                            else
                                last = null;
                        }

                        offset += 10;
                        if (e.Y - offset <= 0)
                            break;
                    }

                    if (last != null &&
                        last.Parent != null)
                    {
                        Module under = last.Parent;
                        int pos = under.Children.IndexOf(last) + 1;
                        if (my_temp_insert != null)
                            if (under.Children.IndexOf(my_temp_insert) >= 0)
                                pos--;
                        insert_blank(temp_mod, under, pos);
                    }
                    else
                    {
                        if (my_temp_insert != null)
                        {
                            my_temp_insert.Parent.Children.Remove(my_temp_insert);
                            my_temp_insert = null;
                        }
                    }
                    my_display.CalculateSpace();
                }
                else if (my_temp_insert != null) //remove the last one
                {
                    my_temp_insert.Parent.Children.Remove(my_temp_insert);
                    my_temp_insert = null;
                }

                //then draw item to be dropped:
                my_display.Refresh();
                /*Graphics g = CreateGraphics();
                my_graphics.Render(CreateGraphics());


                my_clicked.Displayed.GetDisplayArea().Composite(
                    g, my_clicked.Region, new Point(e.X, e.Y));
                */
            }
        }

        void DisplayDocument_MouseDown(object sender, MouseEventArgs e)
        {
            my_clicked = my_display.ModuleAtCoordinate(e.X, e.Y);
        }

        private DisplayElement my_clicked = null;

        void DisplayDocument_MouseUp(object sender, MouseEventArgs e)
        {
            DisplayElement current = my_display.ModuleAtCoordinate(e.X, e.Y);
            if (my_clicked == current)
                my_current_selected = my_display.Click(e.X, e.Y);
            else if (current != null)
            {
                if (my_temp_insert != null)
                {
                    my_temp_insert.Parent.Children.Remove(my_temp_insert);
                    my_temp_insert = null;
                }

                if (my_clicked.Displayed.Parent == null)
                    return;

                my_clicked.Displayed.Parent.Children.Remove(my_clicked.Displayed);

                Module up = current.Displayed;
                while (up.Parent != null)
                {
                    if (up == my_clicked.Displayed)
                    {
                        MessageBox.Show("Can't drag an element into itself!");
                        return;
                    }
                    up = up.Parent;
                }

                current.Displayed.Parent.Children.Insert(
                    current.Displayed.Parent.Children.IndexOf(current.Displayed) + 1,
                    my_clicked.Displayed);


                my_display.CalculateSpace();
                my_display.Redraw();
            }
            my_clicked = null;
        }

        #endregion

        #region KEYBOARDCONTROLS
        void my_display_KeyUp(object sender, KeyEventArgs e)
        {
            if (my_current_selected != null)
            {
                if (e.Control)
                {
                    if (e.KeyCode == Keys.Up)
                    {
                        if (my_current_selected.Parent != null)
                        {
                            my_current_selected = my_current_selected.Parent;
                            my_display.Select(my_current_selected);
                            my_display.ScrollTo(my_current_selected);
                        }
                    }
                    else if (e.KeyCode == Keys.Down)
                    {
                        if (my_current_selected.Children.Count > 0)
                        {
                            my_current_selected = my_current_selected.Children[0];
                            my_display.Select(my_current_selected);
                            my_display.ScrollTo(my_current_selected);
                        }
                    }
                    else if (e.KeyCode == Keys.Left)
                    {
                        if (my_current_selected.Parent.Children.IndexOf(my_current_selected)
                            > 0)
                        {
                            my_current_selected = my_current_selected.Parent.Children[
                                my_current_selected.Parent.Children.IndexOf(my_current_selected) - 1];
                            my_display.Select(my_current_selected);
                            my_display.ScrollTo(my_current_selected);
                        }
                    }
                    else if (e.KeyCode == Keys.Right)
                    {
                        if (my_current_selected.Parent.Children.IndexOf(my_current_selected)
                            < my_current_selected.Parent.Children.Count - 1)
                        {
                            my_current_selected = my_current_selected.Parent.Children[
                                my_current_selected.Parent.Children.IndexOf(my_current_selected) + 1];
                            my_display.Select(my_current_selected);
                            my_display.ScrollTo(my_current_selected);
                        }
                    }
                    return;
                }
            }
        }
        #endregion
    }
}
